package com.harmony.pilot.knowledge.service;

import com.harmony.pilot.knowledge.entity.*;
import com.harmony.pilot.knowledge.repository.*;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * 头文件依赖关系分析服务
 * 分析.h/.cpp文件依赖的头文件，建立完整的依赖关系图
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class HeaderDependencyAnalysisService {
    
    private final IncludeDependencyRepository includeDependencyRepository;
    private final FileMetadataRepository fileMetadataRepository;
    private final GnSourceMappingRepository gnSourceMappingRepository;
    
    @Value("${openharmony.code.base-path:../ohcode}")
    private String codeBasePath;
    
    // Include语句的正则表达式
    private static final Pattern INCLUDE_PATTERN = Pattern.compile(
        "^\\s*#include\\s+[\"<]([^>\"]+)[>\"]"
    );
    
    /**
     * 分析文件的头文件依赖
     */
    public List<IncludeDependency> analyzeFileDependencies(String filePath, String code) {
        log.debug("Analyzing header dependencies for: {}", filePath);
        
        List<IncludeDependency> dependencies = new ArrayList<>();
        String[] lines = code.split("\n");
        
        for (int i = 0; i < lines.length; i++) {
            String line = lines[i];
            Matcher matcher = INCLUDE_PATTERN.matcher(line);
            
            if (matcher.find()) {
                String includePath = matcher.group(1);
                
                IncludeDependency dep = new IncludeDependency();
                dep.setFilePath(filePath);
                dep.setIncludePath(includePath);
                dep.setIncludeStatement(line.trim());
                dep.setLineNumber(i + 1);
                dep.setIncludeType(determineIncludeType(includePath));
                
                // 尝试解析实际头文件路径
                String resolvedPath = resolveHeaderPath(filePath, includePath);
                dep.setResolvedPath(resolvedPath);
                dep.setResolved(resolvedPath != null);
                
                dependencies.add(dep);
            }
        }
        
        return dependencies;
    }
    
    /**
     * 批量分析并保存依赖关系
     */
    public void analyzeAndSaveDependencies(List<FileMetadata> files) {
        log.info("Analyzing header dependencies for {} files", files.size());
        
        int processed = 0;
        for (FileMetadata file : files) {
            try {
                // 读取文件内容
                String content = Files.readString(Paths.get(file.getFilePath()));
                
                // 分析依赖
                List<IncludeDependency> deps = analyzeFileDependencies(file.getFilePath(), content);
                
                // 保存依赖关系
                for (IncludeDependency dep : deps) {
                    // 检查是否已存在
                    Optional<IncludeDependency> existing = includeDependencyRepository
                            .findByFilePathAndIncludePath(file.getFilePath(), dep.getIncludePath());
                    
                    if (existing.isEmpty()) {
                        includeDependencyRepository.save(dep);
                    }
                }
                
                processed++;
                if (processed % 100 == 0) {
                    log.info("Processed {}/{} files", processed, files.size());
                }
                
            } catch (Exception e) {
                log.error("Failed to analyze dependencies for: {}", file.getFilePath(), e);
            }
        }
        
        log.info("Header dependency analysis completed: {} files processed", processed);
    }
    
    /**
     * 获取文件的直接依赖（头文件）
     */
    public List<IncludeDependency> getDirectDependencies(String filePath) {
        return includeDependencyRepository.findByFilePath(filePath);
    }
    
    /**
     * 获取文件的递归依赖（依赖的依赖）
     */
    public Set<String> getRecursiveDependencies(String filePath, int maxDepth) {
        Set<String> allDeps = new HashSet<>();
        Set<String> visited = new HashSet<>();
        
        Queue<String> queue = new LinkedList<>();
        queue.offer(filePath);
        visited.add(filePath);
        
        int depth = 0;
        while (!queue.isEmpty() && depth < maxDepth) {
            int levelSize = queue.size();
            depth++;
            
            for (int i = 0; i < levelSize; i++) {
                String currentFile = queue.poll();
                
                List<IncludeDependency> deps = getDirectDependencies(currentFile);
                for (IncludeDependency dep : deps) {
                    if (dep.isResolved() && dep.getResolvedPath() != null) {
                        String resolvedPath = dep.getResolvedPath();
                        
                        if (!visited.contains(resolvedPath)) {
                            visited.add(resolvedPath);
                            allDeps.add(resolvedPath);
                            queue.offer(resolvedPath);
                        }
                    }
                }
            }
        }
        
        return allDeps;
    }
    
    /**
     * 查找依赖某个头文件的所有文件
     */
    public List<IncludeDependency> findFilesDependingOn(String headerFilePath) {
        return includeDependencyRepository.findByResolvedPath(headerFilePath);
    }
    
    /**
     * 验证BUILD.gn中的include_dirs是否包含所有需要的头文件路径
     */
    public List<String> validateGnIncludeDirs(Long gnTargetId, List<String> includeDirs) {
        // 获取GN target的所有源文件
        List<GnSourceMapping> mappings = gnSourceMappingRepository.findByGnTargetId(gnTargetId);
        
        List<String> missingIncludes = new ArrayList<>();
        
        for (GnSourceMapping mapping : mappings) {
            List<IncludeDependency> deps = getDirectDependencies(mapping.getSourceFileAbsolutePath());
            
            for (IncludeDependency dep : deps) {
                if (dep.isResolved() && dep.getResolvedPath() != null) {
                    // 检查include_dirs是否包含该头文件的路径
                    boolean found = includeDirs.stream()
                            .anyMatch(dir -> dep.getResolvedPath().contains(dir));
                    
                    if (!found) {
                        missingIncludes.add(dep.getIncludePath());
                    }
                }
            }
        }
        
        return missingIncludes.stream().distinct().collect(Collectors.toList());
    }
    
    /**
     * 确定include类型
     */
    private String determineIncludeType(String includePath) {
        if (includePath.startsWith("/") || includePath.startsWith("foundation/") ||
            includePath.startsWith("commonlibrary/") || includePath.startsWith("base/")) {
            return "LOCAL";
        } else if (includePath.startsWith("<") || includePath.contains("/usr/")) {
            return "SYSTEM";
        } else {
            return "RELATIVE";
        }
    }
    
    /**
     * 解析头文件的实际路径
     */
    private String resolveHeaderPath(String sourceFilePath, String includePath) {
        try {
            Path sourceDir = Paths.get(sourceFilePath).getParent();
            
            // 如果是相对路径
            if (!includePath.startsWith("/")) {
                Path headerPath = sourceDir.resolve(includePath).normalize();
                if (Files.exists(headerPath)) {
                    return headerPath.toString();
                }
            }
            
            // 尝试从codeBasePath解析
            Path basePath = Paths.get(codeBasePath);
            Path headerPath = basePath.resolve(includePath).normalize();
            if (Files.exists(headerPath)) {
                return headerPath.toString();
            }
            
            // 尝试查找（递归查找）
            return findHeaderFile(includePath, basePath);
            
        } catch (Exception e) {
            log.debug("Failed to resolve header path: {}", includePath, e);
            return null;
        }
    }
    
    /**
     * 递归查找头文件
     */
    private String findHeaderFile(String includePath, Path searchDir) {
        try {
            return Files.walk(searchDir, 10)
                    .filter(Files::isRegularFile)
                    .filter(path -> {
                        String fileName = path.getFileName().toString();
                        String searchName = includePath.contains("/") ?
                                includePath.substring(includePath.lastIndexOf("/") + 1) :
                                includePath;
                        return fileName.equals(searchName) || 
                               path.toString().endsWith(includePath);
                    })
                    .findFirst()
                    .map(Path::toString)
                    .orElse(null);
        } catch (Exception e) {
            return null;
        }
    }
}

